package com.xinhe.cn.cpbox.service.impl;


import cn.hutool.core.date.DateUtil;
import com.xinhe.cn.cpbox.entity.dto.CountPayDto;
import com.xinhe.cn.cpbox.entity.po.*;
import com.xinhe.cn.cpbox.mapper.*;
import com.xinhe.cn.cpbox.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author HB
 * @date 2021/10/09 15:13
 */
@Slf4j
@Service
public class OrderServiceImpl implements OrderService {
    @Autowired
    UserInfoMapper userInfoMapper;
    @Autowired
    UserOrderMapper userOrderMapper;
    @Autowired
    MatchMakerMapper matchMakerMapper;
    @Autowired
    UserRecordMapper userRecordMapper;
    @Autowired
    SystemConstantMapper systemConstantMapper;

    /**
     * 扫描某个时间段的订单，计算提成并生成订单记录
     *
     * @param startTime 开始时间，包含
     * @param endTime   结束时间，不包含
     */
    @Override
    @Transactional(rollbackFor = {RuntimeException.class, Error.class})
    public void summaryMoney(String startTime, String endTime) {
        // 拉出时间段内所有已支付且有直属月老的用户订单
        List<UserOrder> orders = userOrderMapper.getPayOrderByTime(startTime, endTime);

        try {
            if (orders.size() != 0) {
                // 获取所有支付者的id，去重
                List<String> payUserIds = orders.stream().map(UserOrder::getOpenId).collect(Collectors.toList()).stream().distinct().collect(Collectors.toList());
                // 获取所有支付者信息(为了通过extendId获取直属月老信息)
                List<UserInfo> payUserInfos = userInfoMapper.selectBatchIds(payUserIds);
                // 根据支付者信息提取直属月老id，获取到直属月老信息
                List<MatchMaker> linkMakers = matchMakerMapper.selectBatchIds(payUserInfos.stream().map(UserInfo::getExtendId).distinct().collect(Collectors.toList()));
                // 生成<用户-直属月老>关系map，key为消费用户的id，value为直属月老的信息
                Map<String, MatchMaker> linkBetweenUserAndMaker = new HashMap<>();
                payUserInfos.forEach(
                        oneUser -> {
                            String extendId = oneUser.getExtendId();
                            for (MatchMaker linkMaker : linkMakers) {
                                if (extendId.equals(linkMaker.getMatchMakerId())) {
                                    linkBetweenUserAndMaker.put(oneUser.getOpenId(), linkMaker);
                                    break;
                                }
                            }
                        }
                );

                // 抽取所有产生收益的月老(包括直属、上级、上上级)的id，去重
                Set<String> moneyMakerIds = new HashSet<>();
                moneyMakerIds.addAll(linkMakers.stream().map(MatchMaker::getMatchMakerId).distinct().collect(Collectors.toList())); // 直属月老
                moneyMakerIds.addAll(linkMakers.stream().map(MatchMaker::getParentId).distinct().collect(Collectors.toList())); // 上级月老
                moneyMakerIds.addAll(linkMakers.stream().map(MatchMaker::getGrandparentId).distinct().collect(Collectors.toList())); // 上上级月老
                moneyMakerIds.remove(null); // 去除null值
                // 为所有产生收益的月老生成对应的DTO类，存入<月老-收益>map，key为月老的id，value为月老的收入计算类
                Map<String, CountPayDto> countMap = new HashMap<>();
                moneyMakerIds.forEach(
                        one -> {
                            CountPayDto countPayDto = new CountPayDto(one);
                            countMap.put(one, countPayDto);
                        }
                );

                // 遍历订单，计算收入
                orders.forEach(
                        oneOrder -> {
                            String money = oneOrder.getMoney(); // 消费的金额，单位：分
                            MatchMaker matchMaker = linkBetweenUserAndMaker.get(oneOrder.getOpenId());  // 获取直属月老

                            // 直属月老收入
                            countMap.get(matchMaker.getMatchMakerId()).addMoney(1, new BigDecimal(money));
                            // 上级月老收入
                            if (StringUtils.isNotBlank(matchMaker.getParentId())) {
                                countMap.get(matchMaker.getParentId()).addMoney(2, new BigDecimal(money));
                            }
                            // 上上级月老收入
                            if (StringUtils.isNotBlank(matchMaker.getGrandparentId())) {
                                countMap.get(matchMaker.getGrandparentId()).addMoney(3, new BigDecimal(money));
                            }
                        }
                );

                // 更新收入并生成用户记录
                String createTime = DateUtil.now();
                countMap.forEach(
                        (matchMakerId, countPay) -> {
                            // 应更新对应的金额
                            BigDecimal addMoney = new BigDecimal(0.00);

                            // 直属用户收益增加50%
                            countPay.linkMoney = countPay.linkMoney.multiply(CountPayDto.one).multiply(CountPayDto.fifty);
                            addMoney = addMoney.add(countPay.linkMoney);
                            // 生成用户记录
                            UserRecord userRecord1 = new UserRecord();
                            userRecord1.setOpenId(matchMakerId);
                            userRecord1.setCreateTime(createTime);
                            userRecord1.setContent("直属用户收益+" + countPay.linkMoney.setScale(2, BigDecimal.ROUND_DOWN).toString());
                            userRecordMapper.insert(userRecord1);

                            if (countPay.chileMoney.compareTo(CountPayDto.zero) != 0) {
                                // 下级用户收益增加10%
                                countPay.chileMoney = countPay.chileMoney.multiply(CountPayDto.one).multiply(CountPayDto.ten);
                                addMoney = addMoney.add(countPay.chileMoney);
                                // 生成用户记录
                                UserRecord userRecord2 = new UserRecord();
                                userRecord2.setOpenId(matchMakerId);
                                userRecord2.setCreateTime(createTime);
                                userRecord2.setContent("下级月老用户收益+" + countPay.chileMoney.setScale(2, BigDecimal.ROUND_DOWN).toString());
                                userRecordMapper.insert(userRecord2);
                            }

                            if (countPay.grandchildMoney.compareTo(CountPayDto.zero) != 0) {
                                // 下下级用户收益增加5%
                                countPay.grandchildMoney = countPay.grandchildMoney.multiply(CountPayDto.one).multiply(CountPayDto.five);
                                addMoney = addMoney.add(countPay.grandchildMoney);
                                // 生成用户记录
                                UserRecord userRecord3 = new UserRecord();
                                userRecord3.setOpenId(matchMakerId);
                                userRecord3.setCreateTime(createTime);
                                userRecord3.setContent("下下级月老用户收益+" + countPay.grandchildMoney.setScale(2, BigDecimal.ROUND_DOWN).toString());
                                userRecordMapper.insert(userRecord3);
                            }

                            // 更新收益金额
                            addMoney = addMoney.setScale(2, BigDecimal.ROUND_DOWN); // 直接删除多余的小数位，如2.355会变成2.35
                            matchMakerMapper.addMoney(addMoney.toString(), matchMakerId);
                        }
                );
            }
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); // 事务生效，异常回滚
            systemConstantMapper.insert(new SystemConstant("error-" + DateUtil.now(), DateUtil.now() + "计算提成出现异常，请检查log"));
            log.error("统计提成出现异常: \n" + e);
        }

        log.info("计算提成并生成用户记录：{} 个订单", orders.size());
    }

    /**
     * 清理某个时间前的未支付订单
     *
     * @param time 时间
     */
    @Override
    public void clearNoPayOrder(String time) {
        int num = userOrderMapper.deleteNoPayOrder(time);
        log.info("12点清空无用未支付订单: {}", num);
    }
}
